package MultiThread;

import java.util.Random;
//importe
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.IOException;
import java.util.concurrent.ExecutionException;

import MonteCarloGUI.MonteCarloGUI;

//import fr.ece.ing4.si.yahoo.YahooFinance;



public class MonteCarlo {
//POUr Threads
	  public double calculThread() throws InterruptedException, ExecutionException { 
		  //generic
	    final int numberOfCores = Runtime.getRuntime().availableProcessors();
	    final double blockingCoefficient = 0.05;
	    final int poolSize = (int)(numberOfCores / (1 - blockingCoefficient));
	    //System.out.println("Number of Cores available is " + numberOfCores);
	    //System.out.println("Pool size is " + poolSize);
	    
	    final List<Callable<Double>> partitions = new ArrayList<Callable<Double>>();
		
		dt = T/nSteps;
		Drift = (b - (Math.pow(v,2) / 2)) * dt; 
		vSqrdt = v * Math.sqrt(dt); 
		
	    //ici thread lances
	    for(int i=0; i<nSimulations; i++) {
	        partitions.add(new Callable<Double>() {
	          public Double call() throws Exception {
	        	  //Fonction a executer
	      			St=S;
		        	  Random rand = new Random();
	      			for (int j=0; j<nSteps; j++) {
	      			 St=St*Math.exp(Drift+vSqrdt*rand.nextGaussian());
	      			 }
	      			if (z==1) {
	      			//	System.out.println("Good"); //if you uncomment this line the result will be good but is not with it commented. 
	      			// It seems to be a special trick from the Random/nextGaussian implementation
	      				Sum=Math.max(St-X, 0);
	      			}
	      			else { 
	      				System.out.println("lol");
	      				Sum=Math.max(X-St, 0);
	      			}
	      				
	        	  return Sum;
	        	  //Fin de Fonction a executer 
	          }        
	        });
	      }
	    
	    final ExecutorService executorPool = Executors.newFixedThreadPool(poolSize);    
	    final List<Future<Double>> valueOfStocks = executorPool.invokeAll(partitions, 1000000, TimeUnit.SECONDS);
	    
	    double tSum=0;
	    for(final Future<Double> subSum : valueOfStocks)
	    	tSum+=subSum.get();
	    executorPool.shutdown();  
		double result=Math.exp(-r*T)*tSum/nSimulations;
		return result;
	  }

	  public static void main(final String[] args) throws ExecutionException, InterruptedException, IOException { 
		final long start = System.nanoTime();
		//new MonteCarlo(40, 50, 0.06, 0.5, 0.1, 0.45, 168, 100000, "c").calculThread();
		MonteCarloGUI gui = new MonteCarloGUI();
	    final long end = System.nanoTime();
	    System.out.println("Time (seconds) taken " + (end - start)/1.0e9);
	  }
	
//Pour MonteCarlo
	String CallPutFlag;
	double S, X, T, r, b, v;
	int nSteps, nSimulations;
	double dt, St, Sum, Drift, vSqrdt;
	//TESTS
	int z;
	public MonteCarlo(double S, double X, double r, double T, double b, double v, int Steps, int Simul, String PC) {
		this.S=S; 
		this.X=X; 
		this.r=r; 
		this.T=T; 
		this.b=b; 
		this.v=v; 
		this.nSteps=Steps; 
		this.nSimulations=Simul;
		if (PC=="c")
			this.z=1;
		else
			this.z=-1;
	}
	
	
	
}
